﻿using System;
using System.Collections.Generic;
using System.Text;

namespace LocalizationTest.Tools
{
  abstract class Function
  {
    public void FindMinium(
    out double minimalValue,
    out double[] positionOfMinimalValue,
    out double maximalValue,
    out double[] positionOfMaximalValue,
    double[] rangeMin,
    double[] rangeMax,
    double[] step
    )
    {
      TimeTool.Start("FindMinimun");

      maximalValue = Double.MinValue;
      minimalValue = Double.MaxValue;

      positionOfMinimalValue = null;
      positionOfMaximalValue = null;

      double[] currentVector = new double[step.Length];
      currentVector = (double[])rangeMin.Clone();

      bool continueLoop = true;
      double loopCounter = 0;
      while (continueLoop)
      {
        double value = Evaluate(currentVector);
        if (value > maximalValue)
        {
          maximalValue = value;
          positionOfMaximalValue = currentVector;
        }
        if (value < minimalValue)
        {
          minimalValue = value;
          positionOfMinimalValue = currentVector;
        }
        continueLoop = GetNextInIteration(currentVector, rangeMin, rangeMax, step, out currentVector);
        loopCounter++;
      }
      DebugTextTool.Output("number of loops: " + loopCounter);
      TimeTool.Stop("FindMinimun");
    }

    public bool GetNextInIteration(
    double[] current,
    double[] rangeMin,
    double[] rangeMax,
    double[] step,
    out double[] next
      )
    {
      next = new double[current.Length];
      for (int i = 0; i < current.Length; i++) next[i] = current[i];
      int j;
      for (j = 0; j < current.Length; j++)
      {
        if (next[j] + step[j] <= rangeMax[j]) 
        {
          next[j] += step[j];
          break;
        }
        else next[j] = rangeMin[j];
      }
      if(j==current.Length) return false;
      return true;
    }

    public void FindMinimalRange(
      double tolerance,
    double[] rangeMin,
    double[] rangeMax,
    double[] step
      )
    {
      double[] currentVector = new double[step.Length];
      currentVector = (double[])rangeMin.Clone();

      bool continueLoop = true;
      while (continueLoop)
      {
        double value = Evaluate(currentVector);
        if (value < tolerance)
        {
          double radius = Math.Min(value / 1000.0, 20);
          DebugDrawingTool.CreateCircle("world:function", new Vector2(currentVector[0], currentVector[1]), radius, 2, System.Drawing.Color.Red);
        }
        continueLoop = GetNextInIteration(currentVector, rangeMin, rangeMax, step, out currentVector);
      }
    }

    public abstract double Evaluate(double[] vector);
  }
}
